#include "Drv_MPU6050.h"
#include "BitBand.h"
#include "Drv_TIM.h"
#include "stdio.h"

#define MPU_IIC_SCL    PDout(9)
#define MPU_IIC_SDA_O  PEout(15)
#define MPU_IIC_SDA_I  PEin(15)

#define SET_SDA_IN()    {GPIOE->MODER&=~(3<<(9*2));GPIOE->MODER|=0<<(9*2);}
#define SET_SDA_OUT()   {GPIOE->MODER&=~(3<<(9*2));GPIOE->MODER|=1<<(9*2);}
#define IIC_DELAY(x)    delay_US(x)


#define SIMU_IIC
#ifdef  SIMU_IIC 

void IIC_Init()
{
  MPU_IIC_SCL = 1;
  MPU_IIC_SDA_O = 1;
}

void IIC_Start()
{
  SET_SDA_OUT();
  MPU_IIC_SCL = 1;
  MPU_IIC_SDA_O = 1;
  IIC_DELAY(4);
  MPU_IIC_SDA_O = 0;
  IIC_DELAY(4);
  MPU_IIC_SCL = 0;
}

void IIC_Stop()
{
  SET_SDA_OUT();
  MPU_IIC_SCL = 0;
  MPU_IIC_SDA_O = 0;
  IIC_DELAY(4);
  MPU_IIC_SCL = 1;
  MPU_IIC_SDA_O = 1;
  IIC_DELAY(4);
}

// 1: Failed 0: success
uint8_t IIC_WaitAck()
{
  uint8_t ucErrTime = 0;

  SET_SDA_IN();
  MPU_IIC_SDA_O = 1; IIC_DELAY(1);
  MPU_IIC_SCL = 1;   IIC_DELAY(1);
  while (MPU_IIC_SDA_I)
  {
    ++ucErrTime;
    if(ucErrTime > 250)
    {
      IIC_Stop();
      return 1;
    }
  }
  MPU_IIC_SCL = 0;
  return 0;
}

void IIC_Ack()
{
  SET_SDA_OUT();
  MPU_IIC_SCL = 0;
  MPU_IIC_SDA_O = 0;
  IIC_DELAY(2);
  MPU_IIC_SCL = 1;
  IIC_DELAY(2);
  MPU_IIC_SCL = 0;
}

void IIC_NAck()
{
  SET_SDA_OUT();
  MPU_IIC_SCL = 0;
  MPU_IIC_SDA_O = 1;
  IIC_DELAY(2);
  MPU_IIC_SCL = 1;
  IIC_DELAY(2);
  MPU_IIC_SCL = 0;
}

void IIC_SendByte(uint8_t byte)
{
  uint8_t i;

  SET_SDA_OUT();
  MPU_IIC_SCL = 0;
  for(i=0; i<8; ++i)
  {
    MPU_IIC_SDA_O = (byte &0x80) >> 7;
    byte <<= 1;
    IIC_DELAY(2);
    MPU_IIC_SCL = 1;
    IIC_DELAY(2);
    MPU_IIC_SCL = 0;
    IIC_DELAY(2);
  }
}

// ack = 0: NAck 1: Ack
uint8_t IIC_ReadByte(uint8_t ack)
{
  uint8_t i, byte;

  SET_SDA_IN();
  for(i=0; i<8; ++i)
  {
    MPU_IIC_SCL = 0;
    IIC_DELAY(2);
    MPU_IIC_SCL = 1;
    byte <<= 1;
    if(MPU_IIC_SDA_I)
      ++byte;
    IIC_DELAY(1);
  }
  if(ack)
    IIC_Ack();
  else
    IIC_NAck();
  
  return byte;
}

#endif

#define MPU_ADDR 0x68 // AD0 GND

#define MPU_REG
#ifdef MPU_REG

//#define MPU_ACCEL_OFFS_REG		0X06	//accel_offs寄存器,可读取版本号,寄存器手册未提到
//#define MPU_PROD_ID_REG			0X0C	//prod id寄存器,在寄存器手册未提到
#define MPU_SELF_TESTX_REG		0X0D	//自检寄存器X
#define MPU_SELF_TESTY_REG		0X0E	//自检寄存器Y
#define MPU_SELF_TESTZ_REG		0X0F	//自检寄存器Z
#define MPU_SELF_TESTA_REG		0X10	//自检寄存器A
#define MPU_SAMPLE_RATE_REG		0X19	//采样频率分频器
#define MPU_CFG_REG				0X1A	//配置寄存器
#define MPU_GYRO_CFG_REG		0X1B	//陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG		0X1C	//加速度计配置寄存器
#define MPU_MOTION_DET_REG		0X1F	//运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG			0X23	//FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG		0X24	//IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG	0X25	//IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG			0X26	//IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG	0X27	//IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG	0X28	//IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG			0X29	//IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG	0X2A	//IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG	0X2B	//IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG			0X2C	//IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG	0X2D	//IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG	0X2E	//IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG			0X2F	//IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG	0X30	//IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG	0X31	//IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG			0X32	//IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG		0X33	//IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG	0X34	//IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG		0X35	//IIC从机4读数据寄存器

#define MPU_I2CMST_STA_REG		0X36	//IIC主机状态寄存器
#define MPU_INTBP_CFG_REG		0X37	//中断/旁路设置寄存器
#define MPU_INT_EN_REG			0X38	//中断使能寄存器
#define MPU_INT_STA_REG			0X3A	//中断状态寄存器

#define MPU_ACCEL_XOUTH_REG		0X3B	//加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG		0X3C	//加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG		0X3D	//加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG		0X3E	//加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG		0X3F	//加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG		0X40	//加速度值,Z轴低8位寄存器

#define MPU_TEMP_OUTH_REG		0X41	//温度值高八位寄存器
#define MPU_TEMP_OUTL_REG		0X42	//温度值低8位寄存器

#define MPU_GYRO_XOUTH_REG		0X43	//陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG		0X44	//陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG		0X45	//陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG		0X46	//陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG		0X47	//陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG		0X48	//陀螺仪值,Z轴低8位寄存器

#define MPU_I2CSLV0_DO_REG		0X63	//IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG		0X64	//IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG		0X65	//IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG		0X66	//IIC从机3数据寄存器

#define MPU_I2CMST_DELAY_REG	0X67	//IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG		0X68	//信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG	0X69	//运动检测控制寄存器
#define MPU_USER_CTRL_REG		0X6A	//用户控制寄存器
#define MPU_PWR_MGMT1_REG		0X6B	//电源管理寄存器1
#define MPU_PWR_MGMT2_REG		0X6C	//电源管理寄存器2 
#define MPU_FIFO_CNTH_REG		0X72	//FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG		0X73	//FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG			0X74	//FIFO读写寄存器
#define MPU_DEVICE_ID_REG		0X75	//器件ID寄存器

#endif

uint8_t MPU_WriteByte(uint8_t reg, uint8_t data)
{
  IIC_Start();
  IIC_SendByte((MPU_ADDR<<1) |0);
  if(IIC_WaitAck())
  {
    IIC_Stop();
    return 1;
  }
  IIC_SendByte(reg);
  IIC_WaitAck();
  IIC_SendByte(data);
  if(IIC_WaitAck())
  {
    IIC_Stop();
    return 1;
  }
  else{
    IIC_Stop();
    return 0;
  }
}

uint8_t MPU_ReadByte(uint8_t reg)
{
  uint8_t byte;

  IIC_Start();
  IIC_SendByte((MPU_ADDR<<1) |0);
  IIC_WaitAck();
  IIC_SendByte(reg);
  IIC_WaitAck();

  IIC_Start();
  IIC_SendByte((MPU_ADDR<<1) |1);
  IIC_WaitAck();
  byte = IIC_ReadByte(0);
  IIC_Stop();

  return byte;
}

uint8_t MPU_WriteBytes(uint8_t addr, uint8_t reg, uint8_t length, uint8_t *byteArray)
{
  uint8_t i;

  IIC_Start();
  IIC_SendByte((addr<<1) |0);
  if(IIC_WaitAck())
  {
    IIC_Stop();
    return 1;
  }
  IIC_SendByte(reg);
  IIC_WaitAck();
  for(i=0; i<length; ++i)
  {
    IIC_SendByte(byteArray[i]);
    if(IIC_WaitAck())
    {
      IIC_Stop();
      return 1;
    }
  }
  IIC_Stop();
  return 0;
}

uint8_t MPU_ReadBytes(uint8_t addr, uint8_t reg, uint8_t length, uint8_t *byteArray)
{
  uint8_t i;

  IIC_Start();
  IIC_SendByte((addr<<1) |0);
  if(IIC_WaitAck())
  {
    IIC_Stop();
    return 1;
  }
  IIC_SendByte(reg);
  IIC_WaitAck();

  IIC_Start();
  IIC_SendByte((addr<<1) |1);
  IIC_WaitAck();
  for(i=0; i<length; ++i)
  {
    *byteArray = IIC_ReadByte( i != length - 1 );
    ++byteArray;
  }
  IIC_Stop();
  return 0;
}

uint8_t MPU_Init()
{
  uint8_t recvID;
  uint8_t gyro_level, accel_level, lpf_level;
  uint16_t rate, lpf;

  IIC_Init();
  MPU_WriteByte(MPU_PWR_MGMT1_REG, 0x80); // 复位
  HAL_Delay(100);
  MPU_WriteByte(MPU_PWR_MGMT1_REG, 0x00); // 唤醒

  recvID = MPU_ReadByte(MPU_DEVICE_ID_REG);
  printf("%x\n", recvID);
  if(recvID == MPU_ADDR)
  {
    gyro_level = 3;
    accel_level = 0;
    rate = 50;
    lpf = rate / 2;
    if(lpf >= 188)        lpf_level = 1;
    else if(lpf >= 98)    lpf_level = 2;
    else if(lpf >= 42)    lpf_level = 3;
    else if(lpf >= 20)    lpf_level = 4;
    else if(lpf >= 10)    lpf_level = 5;
    else                  lpf_level = 6;

    // 设置MPU6050陀螺仪传感器满量程范围
    //fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
    MPU_WriteByte(MPU_GYRO_CFG_REG, gyro_level << 3);

    //设置MPU6050加速度传感器满量程范围
    //fsr:0,±2g;1,±4g;2,±8g;3,±16g
    MPU_WriteByte(MPU_ACCEL_CFG_REG, accel_level << 3);

    //设置MPU6050的采样率(假定Fs=1KHz)
    //rate:4~1000(Hz)
    MPU_WriteByte(MPU_SAMPLE_RATE_REG, (1000/rate - 1));

    //设置MPU6050的数字低通滤波器
    //lpf:数字低通滤波频率(Hz)
    MPU_WriteByte(MPU_CFG_REG, lpf_level);

    MPU_WriteByte(MPU_INT_EN_REG, 0x00); // 关闭所有中断
    MPU_WriteByte(MPU_USER_CTRL_REG, 0x00); // I2C主模式关闭
    MPU_WriteByte(MPU_FIFO_EN_REG, 0x00); // 关闭FIFO
    MPU_WriteByte(MPU_INTBP_CFG_REG, 0x80); // INT引脚低电平有效

    MPU_WriteByte(MPU_PWR_MGMT1_REG, 0x01); // 设置CLKSEL, PLL X轴为参考
    MPU_WriteByte(MPU_PWR_MGMT2_REG, 0x00); // 加速度计 陀螺仪 工作
    
    return 0;
  }
  else
  {
    return 1;
  }
}

int8_t MPU_GetGyroscope(int16_t *gx, int16_t *gy, int16_t *gz)
{
  uint8_t buf[6], res;

  res = MPU_ReadBytes(MPU_ADDR, MPU_GYRO_XOUTH_REG, 6, buf);
  if(res == 0)
  {
    *gx = ( (uint16_t)buf[0] << 8) |buf[1];
    *gy = ( (uint16_t)buf[2] << 8) |buf[3];
    *gz = ( (uint16_t)buf[4] << 8) |buf[5];
  }
  return res;
}

int8_t MPU_GetAccelerometer(int16_t *ax, int16_t *ay, int16_t *az)
{
  uint8_t buf[6], res;

  res = MPU_ReadBytes(MPU_ADDR, MPU_ACCEL_XOUTH_REG, 6, buf);
  if(res == 0)
  {
    *ax = ( (uint16_t)buf[0] << 8) | buf[1];
    *ay = ( (uint16_t)buf[2] << 8) | buf[3];
    *az = ( (uint16_t)buf[4] << 8) | buf[5];
  }
  return res;
}

int16_t MPU_GetTemperature()
{
  uint8_t buf[2];
  int16_t raw;
  float tmp;

  MPU_ReadBytes(MPU_ADDR, MPU_TEMP_OUTH_REG, 2, buf);
  raw = ( (uint16_t)buf[0] << 8) |buf[1];
  tmp = 36.53 + (double)raw/340;
  return tmp*100;
}
